# TODO: image scale limit 
# TODO: marker image front/end - 
# TODO: frame+ shadow - 
# TODO: speed with many markers -
# TODO: make front - 

# TODO: acceleration problem - 
# TODO: throwable

# TODO: opacity - 
# TODO: bug in isSelected/free init -
# TODO: opacity bug -
# TODO: frame color -
# TODO: random defaulting - 
# TODO: rotation random when repulsive motion - 

# TODO: Reset key, fps key: get_fps()
# TODO: VIDEO
# TODO: minimum/maximum size - 
# TODO: bug in marker -
# TODO: frame size - 
# 
# TODO: video function - 
# TODO: bug2 in acceleration 

# TODO: fid rotation bug in rejection

from pymt import *
from OpenGL.GL import *
import os, random, math

current_dir = os.path.dirname(__file__)
groups = []

# prev marker pos
prevMarkerPos = [(0,0,0),(0,0,0),(0,0,0),(0,0,0),(0,0,0)]
prevMakerMoveTime = [0,0,0,0,0]
prevMarkerWaitingState = [False, False, False, False, False]
prevMarkerTouch = [None,None,None,None,None ]
markerState  = [False, False, False, False, False]

# constant
MARKER_R = 80
DEFAULT_SCALE = 0.1
SCALE_BY_ROTATION_LIMIT = 3
PI = 3.141592
OPACITY_BW = 0.5
MAKRKER_DELAY = 0.8
ROTATION_SCALE_FACTOR = 2.0


class Background(MTWidget):
	def __init__(self):
		super(Background, self).__init__()
		self.background = Image(os.path.join(current_dir, 'data2', 'background.jpg'))

	def draw(self):
		w = getWindow()
		w.gradient = False
		set_color(1, 1, 1)
		drawTexturedRectangle(self.background.texture, size=w.size)
		
		

class FiducialTest(MTWidget):
	imgFid = None
	def __init__(self, **kwargs):
		super(FiducialTest, self).__init__(**kwargs)
		self.touch_positions = {}
		self.orot = [0,0,0,0,0]
		self.rot = [0,0,0,0,0]
		self.preRot = [0,0,0,0,0]
		self.rotState = [0,0,0,0,0]
	
	def makeFrontImgs(self, fid):
		w = getWindow()
		childList = []
		for i in xrange(0,w.children.__len__()):
			child = w.children[i]
			if child.__class__ == MTScatterImageGSTAR and child.group == fid:
				childList.append(child)
		for i in childList:
			i.bring_to_front()
	
	def draw(self):
		# TODO: make a widget 
		for touch in getCurrentTouches():
			
			set_color(1,1,1,1)
			
			if 'markerid' in touch.profile:
				FiducialTest.imgFid.pos= (-FiducialTest.imgFid.width/2, -FiducialTest.imgFid.height/2, 0)
				with gx_matrix:
					glTranslatef(touch.x, touch.y, 0)
					glRotatef(-touch.angle/math.pi * 180., 0,0,1)
					FiducialTest.imgFid.draw()
	
	def on_touch_down(self, touch):
		if 'markerid' in touch.profile:

			# fid id
			fid = touch.fid % 5
			
			# change marker state
			markerState[fid] = True
			
			# save original rotation
			self.orot[fid] = touch.a
			self.rotState[fid] = 0
			self.preRot[fid] = 0
			
			# get group imgs 
			w = getWindow()
			
			#make front
			self.makeFrontImgs(fid)
				
			# make center
			self.on_touch_move(touch)
			
			# marker front
			self.bring_to_front()

			return True
		else:
			pass
			


	def on_touch_move(self, touch):
		if 'markerid' in touch.profile:
			# fid id
			fid = touch.fid % 5
			
			# change marker state
			markerState[fid] = True
			
			# time stamp
			prevMakerMoveTime[fid] = getClock().get_time()
			
			# if same pos, then return 
			if prevMarkerPos[fid] == (touch.x, touch.y, touch.a):
				return
			else: 
				prevMarkerPos[fid] = (touch.x, touch.y, touch.a)
				
			w = getWindow()
			
			# prepare rotation effect
			rotFactor = touch.a - self.orot[fid]
			if rotFactor - self.preRot[fid] > PI:
				self.rotState[fid] -= 1
			elif rotFactor - self.preRot[fid] < -PI:
				self.rotState[fid] += 1
			self.preRot[fid] = rotFactor
			
			rotFactor += (2*PI)*self.rotState[fid]
			
			# make front
			self.makeFrontImgs(fid)
			
			# marker front
			self.bring_to_front()

			# get group imgs 
			j = 0
			delta = 2*PI/imgNum[fid]
			
			for i in xrange(0,w.children.__len__()):
				child = w.children[i]
				if child.__class__ == MTScatterImageGSTAR and child.group ==  touch.fid % 5:
					child.isSelected = True
					
					# detect collision 
					box =child.bbox
					x = box[0][0] + box[1][0]/2
					y = box[0][1] + box[1][1]/2
					
					dst = math.sqrt((touch.x-x)*(touch.x-x) + (touch.y-y)*(touch.y-y))
					if dst < MARKER_R*2 and child.isFree == True:
						child.isSticking = True
						child.isFree = False
						
			
					# make move
					if child.isFree == False:
						box = child.bbox
						
						scaleFactor = (1 + (rotFactor/(2*PI)))
						scaleFactor *= scaleFactor
						
						if scaleFactor < 1:
							scaleFactor = 1
						elif scaleFactor > 2:
							scaleFactor = 2

						scaleFactor *= DEFAULT_SCALE # initially resized
						fx = -box[1][0]/2+ touch.x + MARKER_R*math.cos(j*delta - rotFactor/2)
						fy = -box[1][1]/2+ touch.y + MARKER_R*math.sin(j*delta - rotFactor/2)
						j += 1


						def animation_complete(self):
							self.isFirstAppear = False
							self.isAnimating = False
													
						
						if child.isFirstAppear:
							if child.isVideo:
								a = Animation(duration=1.0, pos=(fx,fy), scale = scaleFactor*2, alpha_function='ease_out_quint')
							else:
								a = Animation(duration=1.0, pos=(fx,fy), scale = scaleFactor, alpha_function='ease_out_quint')
						
							child.isAnimating = True
							child.isFirstAppear = False

							a.connect('on_complete', animation_complete )

							child.do(a)
						
						elif child.isSticking:
							if child.isVideo:
								a = Animation(duration=0.5, pos=(fx,fy), scale = scaleFactor*2, alpha_function='ease_out_quint')
							else:
								a = Animation(duration=0.5, pos=(fx,fy), scale = scaleFactor, alpha_function='ease_out_quint')

							child.isAnimating = True
							a.connect('on_complete', animation_complete )
							child.do(a)
						
						if not child.isAnimating:
							self.isSticking = False	
							if child.isVideo:
								child.pos =(fx,fy)
								child.scale = scaleFactor*2
							else:
								child.pos =(fx,fy)
								child.scale = scaleFactor
						
						# if video widget, then stop it
						if child.isVideo :
							if child.children[0].player.state == 'playing':
								print "move video init"
								# TODO: bug in video play...
								child.children[0].player.stop()
								child.children[0].player.unload()
								fn = os.path.join(current_dir, 'data2', vidString[child.group]) 
								child.children[0] = MTSimpleVideoGSTAR(filename = fn, bordersize=0)
							
			return True
		else:
			pass
	
	
	def on_touch_up(self, touch):
		if 'markerid' in touch.profile:
			fid = touch.fid % 5
			
			def makeTouchUp(*largs):
				if prevMakerMoveTime[fid] + MAKRKER_DELAY > getClock().get_time():
					print "Time isn't up!!", getClock().get_time()
					return False
				else:
					
					# make finish wating state
					prevMarkerWaitingState[fid] = False
					
					#split
					gImgs = []
					for i in xrange(0,w.children.__len__()):
						child = w.children[i]
						if child.__class__ == MTScatterImageGSTAR and child.group == fid:

							# unselect/unfree imgs
							child.isSelected = False
							child.isFree = False
							child.isFirstAppear = True

							#gImgs.append(i)
							x = int(random.uniform(200, w.width-200))
							y = int(random.uniform(200, w.height-200))
							r = int(random.uniform(0, 360))
							
							if child.isVideo:
								a = Animation(duration=1.5, pos=(x,y), rotation = r, scale = DEFAULT_SCALE*2, alpha_function='ease_out_quint')
							else:
								a = Animation(duration=1.5, pos=(x,y), rotation = r, scale = DEFAULT_SCALE, alpha_function='ease_out_quint')
							child.do(a)
							
							# if video widget, then stop it
							if child.isVideo :
								# TODO: bug in video play...
								print "up video init"
								child.children[0].player.stop()
								child.children[0].player.unload()
								fn = os.path.join(current_dir, 'data2', vidString[child.group]) 
								child.children[0] = MTSimpleVideoGSTAR(filename = fn, bordersize=0)
									
					
					# change marker state
					markerState[fid] = False
					
					# touch history
					prevMarkerTouch[fid] = None
					prevMarkerPos[fid] = (-1,-1,-1)
					
					print "up: ", touch.id
					
			# make wating state
			prevMarkerWaitingState[fid] = True
			
			# time check
			getClock().schedule_once(makeTouchUp, MAKRKER_DELAY)
			
			return True
		else:
			pass

class MTScatterImageGSTAR(MTScatterImage):
	
	def __init__(self, **kwargs):
		self.group = -1
		self.group = kwargs.get('group')
		self.isFree = False
		self.isSelected = True
		
		# animation 
		self.isAnimating = False
		self.isFirstAppear = True
		self.isSticking = False
		
		# video 
		self.isVideo = False
		self.vframe = None		
		
		self.image_color = Image(kwargs.get('fn_color'))
		self.image_bw = Image(kwargs.get('fn_bw'))
		self.image_bw.opacity = OPACITY_BW
		
		super(MTScatterImageGSTAR, self).__init__(**kwargs)
	
	def draw(self):
		self.size			= self.image.size
		
		# video 
		if self.isVideo:
			#self.vframe.size = (self.image.width+80, self.image.height+80)
			
			if self.children[0].player.state == 'playing':
				#self.vframe.pos = (self.image.pos[0]-50, self.image.pos[1]-50)
				self.vframe.draw()
				self.children[0].player.pos = (self.vframe.pos[0]+50, self.vframe.pos[1]+50)
				return True
			else:
				self.children[0].visible = False
				self.image_color.size =self.vframe.size
				self.image_bw.size = self.vframe.size
		
		if self.isSelected == True:
			self.image_color.draw()
		else:
			self.image_bw.draw()
	
	def on_touch_down(self, touch):
		if 'markerid' not in touch.profile: 
			
			self.size			= self.image.size
		
			x, y = touch.x, touch.y
			
			isCollided = self.collide_point(x, y)
			if not isCollided:								# if the touch isnt on the widget we do nothing
				return False
				
			elif isCollided and self.isSelected:
				if touch.is_double_tap:
					if not self.isVideo:
						if self._scale < DEFAULT_SCALE*1.5:
							a = Animation(duration=0.5, scale = DEFAULT_SCALE*2, alpha_function='ease_out_cubic')
						else:
							a = Animation(duration=0.5, scale = DEFAULT_SCALE, alpha_function='ease_out_cubic')
						self.do(a)
			
			elif isCollided and not self.isSelected and not prevMarkerWaitingState[self.group]:	# if unselected and collided, then repulsive force
				
				fx = random.uniform(0.3, 0.7)
				fy = random.uniform(0.3, 0.7)			
				
				fx = int(fx*w.width)
				fy = int(fy*w.height)
				fr = int(random.uniform(0, 360*2))
				
				if self.isVideo:
					a = Animation(duration=0.5, pos=(fx,fy), rotation = fr, scale = DEFAULT_SCALE*2, alpha_function='ease_out_cubic')
				else:
					a = Animation(duration=0.5, pos=(fx,fy), rotation = fr, scale = DEFAULT_SCALE, alpha_function='ease_out_cubic')
				self.do(a)
				
				return True
				
			# make free
			self.isFree = True
			
			# let the child widgets handle the event if they want
			touch.push()
			touch.apply_transform_2d(self.to_local)
			if super(MTScatter, self).on_touch_down(touch):
				touch.pop()
				return True
			touch.pop()

			#grab the touch so we get all it later move events for sure
			touch.grab(self)
			self._last_touch_pos[touch] = touch.pos
			self._touches.append(touch)

			#bring to front if auto_bring to front is on
			if self.auto_bring_to_front:
				self.bring_to_front()
				
			return True
		#else:
		#	pass

	def on_touch_move(self, touch):
		#youminkim@20101030 added
		if 'markerid' not in touch.profile: 
		
			self.size			= self.image.size
			
			x, y = touch.x, touch.y
			# let the child widgets handle the event if they want
			if self.collide_point(x, y) and not touch.grab_current == self:
				touch.push()
				touch.apply_transform_2d(self.to_local)
				if super(MTScatter, self).on_touch_move(touch):
					touch.pop()
					return True
				touch.pop()

			# rotate/scale/translate
			if touch in self._touches and touch.grab_current == self:
				self.transform_with_touch (touch)
				self._last_touch_pos[touch] = touch.pos
			
			# stop porpagating if its within our bounds
			if self.collide_point(x,y):
				return True
			
		#else:
		#	pass

	def on_touch_up(self, touch):
		#youminkim@20101030 added
		if 'markerid' not in touch.profile:
			x, y = touch.x, touch.y
			# if the touch isnt on the widget we do nothing, just try children
			if not touch.grab_current == self:
				touch.push()
				touch.apply_transform_2d(self.to_local)
				if super(MTScatter, self).on_touch_up(touch):
					touch.pop()
					return True
				touch.pop()
			
			# remove it from our saved touches
			if touch in self._touches and touch.grab_state:
				touch.ungrab(self)
				del self._last_touch_pos[touch]
				self._touches.remove(touch)
			
			# video play triggering
			if self.collide_point(touch.x, touch.y) and self.isVideo and self.isSelected:
				"""
				if not self.children[0].player.state == 'playing':
					self.children[0].player.play()
					self.children[0].visible = True
				else:
					self.children[0].player.stop()
					self.children[0].visible = False
				"""
				if touch.is_double_tap:
						self.children[0].player.stop()
						self.children[0].visible = False
				else:
					self.children[0].player.play()
					self.children[0].visible = True
					
			# stop porpagating if its within our bounds
			if self.collide_point(x, y):
				return True

		#else:
		#	pass

class MTSimpleVideoGSTAR(MTWidget):
	
	def __init__(self, filename, **kwargs):
		self._touches = {}
		super(MTSimpleVideoGSTAR, self).__init__(**kwargs)

		# load video
		self.player = Video(filename=filename)
		
	def on_touch_down(self, touch):
		if self.collide_point(touch.x, touch.y):
			self._touches[touch.uid] = (touch.x, touch.y)
		return super(MTSimpleVideoGSTAR, self).on_touch_down(touch)

	def on_touch_up(self, touch):
		if touch.uid in self._touches:
			del self._touches[touch.uid]
		return super(MTSimpleVideoGSTAR, self).on_touch_up(touch)

	def on_update(self):
		self.size = self.player.size
		self.player.update()
		super(MTSimpleVideoGSTAR, self).on_update()

	def draw(self):
		self.player.draw()
		super(MTSimpleVideoGSTAR, self).draw()

	 

def makeBlackAndWhite(*largs):
	for i in xrange(0,w.children.__len__()):
		child = w.children[i]
		if child.__class__ == MTScatterImageGSTAR:
			child.isSelected = False

if __name__ == '__main__':
	w = getWindow()
	
	background = Background()
	w.add_widget(background)
	
	# frame for video
	fn =  os.path.join(current_dir, 'data2', 'vframe.png')
	MTScatterImageGSTAR._frame = Image(fn)
	
	imgNum = [13,13,11,12,9]
	imgString = ['mabinogi','df','3kingdoms','2012','mayple']
	
	#vidString = ['mabinogi_v1.avi','df_v1.avi',None,'2012_v1.avi','mayple_v1.avi']
	#vidFrameString = ['mabinogi_vframe.png','df_vframe.png',None, '2012_vframe.png','mayple_vframe.png']
	
	# modify followings!!
	################################################################
	vidString = ['mabinogi_v1.avi','df_v1.avi',None,'2012_v1.avi','mayple_v1.avi']
	vidFrameString = ['mabinogi_vframe.png','df_vframe.png',None, '2012_vframe.png','mayple_vframe.png']
	################################################################
	
	for itrNum in xrange(0,imgNum.__len__()):
		for i in xrange(1,imgNum[itrNum]+1):
			
				
			fn_color = os.path.join(current_dir, 'data2', imgString[itrNum]+'_%d.png' % i)
			fn_bw = os.path.join(current_dir, 'data2', imgString[itrNum]+'_%d_bw.png' % i)
			x = int(random.uniform(0, w.width))
			y = int(random.uniform(0, w.height))
			r = random.uniform(0, 360)
			pos = (x,y)
			m = MTScatterImageGSTAR(fn_color=fn_color, fn_bw = fn_bw, pos=pos, filename=fn_color, scale=DEFAULT_SCALE, rotation = r, group=itrNum, scale_min = DEFAULT_SCALE, scale_max = 1.0) # TODO: opacity?

			# adding video
			if i == imgNum[itrNum] and vidString[itrNum] != None:	
				
				m.isVideo = True
				m.scale *= 2
				m.scale_min *= 2
				
				fn_frame = os.path.join(current_dir, 'data2', vidFrameString[itrNum])
				m.vframe = Image(fn_frame)
				
				fn = os.path.join(current_dir, 'data2', vidString[itrNum]) 
				v = MTSimpleVideoGSTAR(filename = fn, bordersize=0)
				
				v.visible = True
				connect(v, 'on_resize',m, 'size')
				m.add_widget(v)
				
			w.add_widget(m)
			
	marker = FiducialTest()
	fn =  os.path.join(current_dir, 'data2', 'diskBG.png')
	FiducialTest.imgFid = Image(fn)
	w.add_widget(marker)
	
	# for image loading
	getClock().schedule_once(makeBlackAndWhite, 20)
	
	runTouchApp()
	
